package la.iok.hzsvn.lewin.movie.service;

import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.entity.MovieFile;
import la.iok.hzsvn.lewin.movie.model.DigestInfo;
import la.iok.hzsvn.lewin.movie.model.ObsSignedUrl;
import la.iok.hzsvn.lewin.mybatis.model.PageVo;
import la.iok.hzsvn.lewin.mybatis.service.BaseService;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.Nullable;
import la.iok.hzsvn.share.dfs.model.DfsResult;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.OutputStream;

public interface MovieFileService<T extends MovieFile> extends BaseService<T,Long> {
    /**
     * 保存文件记录
     * @param fileName 文件名
     * @param path 存储路径
     * @param digest 摘要信息
     * @return 保存对象的id
     */
    Long save(@NotNull String fileName, @NotNull String path, @NotNull String digest);

    /**
     * 上传文件
     * @param digest 文件摘要
     * @param file 上传的文件
     * @return 文件对象id
     */
    DfsResult uploadFile(@NotNull String digest, File file);

    /**
     * 上传文件并返回文件记录id
     * @param file 文件对象
     * @return 文件记录id
     */
    Long uploadFile(@NotNull MultipartFile file);

    /**
     * 上传文件并返回文件记录id.如果要上传的文件已经存在,则返回已经存在的记录id
     * @param file 文件对象，不能为空并且文件需要存在
     * @return 文件记录id
     */
    Long uploadFile(@NotNull File file);

    ObsSignedUrl uploadFile(@NotNull DigestInfo digest);

    /**
     * 通过签名url使客户端可以访问obs中的文件
     * @param id 文件id
     * @return 签名url
     */
    ObsSignedUrl obsGet(@Nullable Long id);

    /**
     * 转换为本地文件
     * @param file 上传的文件
     * @return 本地文件
     */
    @NotNull
    File transToLocalFile(@NotNull MultipartFile file);

    /**
     * 引用记数加1
     * @param id 文件id
     */
    void increment(@Nullable Long id);

    /**
     * 引用记录减1
     * @param id 文件id
     */
    void decrement(@Nullable Long id);

    /**
     * 查找文件记录
     * @param digest 摘要信息
     * @return 文件对象
     */
    T select(@Nullable String digest);

    /**
     * 获取文件的摘要信息。如果文件存在并且在文件系统中也存在,那就返回数据库中的摘要信息,否则返回null
     * @param id 文件对象id
     * @return 如果找到并且文件系统中存在返回摘要信息,否则返回null
     */
    @Nullable
    String digest(@Nullable Long id);

    /**
     * 获取文件的存储路径。如果文件存在并且在文件系统中也存在,那就返回数据库中的存储路径,否则返回null
     * @param id 文件对象id
     * @return 如果找到并且文件系统中存在返回存储路径,否则返回null
     */
    String storePath(@Nullable Long id);

    /**
     * 判断文件是否存在。根据记录的文件存储路径在分布式系统中查询文件是否存在
     * @param id 文件对象id
     * @return 存在返回true,否则false
     */
    boolean exist(@Nullable Long id);

    void downloadFile(@NotNull OutputStream os, @Nullable T entity);

    PageVo<T> freeFiles(int page, int limit, Integer fileDeleted);

    void deleteFreeFile(@NotNull Token token, Long id);

    /**
     * 删除空闲文件。此方法不验证权限,调用之前需要先验证权限
     * @param id 文件记录id
     */
    void deleteFreeFileWithoutAuthorityCheck(Long id);

    /**
     * 标记空闲文件为已删除。方法中判断引用记数为0并且检查引用此文件的对象是否已经标记删除文件，都满足的情况下就将记录标记为文件已删除
     * （忽略其他与记录的存储路径相同的文件对象,包括同表或者其他MovieFile的子表)
     * @param token 操作用户
     * @param id 文件记录id
     */
    void markFreeFileDeleted(@NotNull Token token, Long id);
}
